/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1999 PARALLAX SOFTWARE EVE.  ALL RIGHTS RESERVED.
*/

#ifdef HAVE_CONFIG_H
#include <conf.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "descent.h"
#include "error.h"
#include "key.h"
#include "gamefont.h"
#include "iff.h"
#include "u_mem.h"
#include "joy.h"
#include "mouse.h"
#include "kconfig.h"
#include "cockpit.h"
#include "rendermine.h"
#include "endlevel.h"
#include "timer.h"
#include "text.h"
#include "automap.h"
#include "args.h"
#include "input.h"
#include "menu.h"
#include "strutil.h"
#include "collide.h"
#include "menubackground.h"
#include "songs.h"
#include "headlight.h"
#include "ogl_render.h"
#if defined (TACTILE)
#	include "tactile.h"
#endif
#ifdef USE_LINUX_JOY
#	include "joystick.h"
#endif

#ifdef D2X_KEYS
//added/removed by Victor Rachels for adding rebindable keys for these
// KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0
ubyte system_keys [] = { (ubyte) KEY_ESC, (ubyte) KEY_F1, (ubyte) KEY_F2, (ubyte) KEY_F3, (ubyte) KEY_F4, (ubyte) KEY_F5, (ubyte) KEY_F6, (ubyte) KEY_F7, (ubyte) KEY_F8, (ubyte) KEY_F9, (ubyte) KEY_F10, (ubyte) KEY_F11, (ubyte) KEY_F12, (ubyte) KEY_MINUS, (ubyte) KEY_EQUALS, (ubyte) KEY_ALTED+KEY_F9 };
#else
ubyte system_keys [] = { (ubyte) KEY_ESC, (ubyte) KEY_F1, (ubyte) KEY_F2, (ubyte) KEY_F3, (ubyte) KEY_F4, (ubyte) KEY_F5, (ubyte) KEY_F6, (ubyte) KEY_F7, (ubyte) KEY_F8, (ubyte) KEY_F9, (ubyte) KEY_F10, (ubyte) KEY_F11, (ubyte) KEY_F12, (ubyte) KEY_0, (ubyte) KEY_1, (ubyte) KEY_2, (ubyte) KEY_3, (ubyte) KEY_4, (ubyte) KEY_5, (ubyte) KEY_6, (ubyte) KEY_7, (ubyte) KEY_8, (ubyte) KEY_9, (ubyte) KEY_0, (ubyte) KEY_MINUS, (ubyte) KEY_EQUALS, (ubyte) KEY_ALTED+KEY_F9 };
#endif

#define TABLE_CREATION 0

// Array used to 'blink' the cursor while waiting for a keypress.
sbyte fades [64] = { 1,1,1,2,2,3,4,4,5,6,8,9,10,12,13,15,16,17,19,20,22,23,24,26,27,28,28,29,30,30,31,31,31,31,31,30,30,29,28,28,27,26,24,23,22,20,19,17,16,15,13,12,10,9,8,6,5,4,4,3,2,2,1,1 };

//char * yesNoTextIndex [2] = { "N", "Y" };
//char * joybutton_text [28] = { "TRIG", "BTN 1", "BTN 2", "BTN 3", "BTN 4", "", "LEFT", "HAT ", "RIGHT", "", "", "HAT ", "MID", "", "", "HAT ", "", "", "", "HAT ", "TRIG", "LEFT", "RIGHT", "", "UP","DOWN","LEFT", "RIGHT" };
//char * JOYAXIS_TEXT [4] = { "X1", "Y1", "X2", "Y2" };
//char * mouseAxisTextIndex [2] = { "L/R", "F/B" };
//char * mouseButtonTextIndex [3] = { "Left", "Right", "Mid" };

int yesNoTextIndex [2] = { TNUM_N, TNUM_Y };

#ifndef USE_LINUX_JOY
	int joybutton_text [28] =
 { TNUM_BTN_1, TNUM_BTN_2, TNUM_BTN_3, TNUM_BTN_4,
	  -1, TNUM_TRIG, TNUM_LEFT, TNUM_HAT_L,
	 TNUM_RIGHT, -1, TNUM_HAT2_D, TNUM_HAT_R,
	 TNUM_MID, -1, TNUM_HAT2_R, TNUM_HAT_U,
	 TNUM_HAT2_L, -1, TNUM_HAT2_U, TNUM_HAT_D,
	 TNUM_TRIG, TNUM_LEFT, TNUM_RIGHT, -1,
	 TNUM_UP, TNUM_DOWN, TNUM_LEFT, TNUM_RIGHT };

	int joyaxis_text [7] = { TNUM_X1, TNUM_Y1, TNUM_Z1, TNUM_R1, TNUM_P1,TNUM_R1,TNUM_YA1 };
//	int JOYAXIS_TEXT [4] = { TNUM_X1, TNUM_Y1, TNUM_X2, TNUM_Y2 };
#endif

#if 0
#	define JOYAXIS_TEXT(v)		joyaxis_text [ (v) % MAX_AXES_PER_JOYSTICK]
#	define JOYBUTTON_TEXT(v)	joybutton_text [ (v) % MAX_BUTTONS_PER_JOYSTICK]
#endif

int mouseAxisTextIndex [3] = {TNUM_L_R, TNUM_F_B, TNUM_Z1};
int mouseButtonTextIndex [3] = {TNUM_LEFT, TNUM_RIGHT, TNUM_MID};
const char * extraMouseButtonTextIndex [13] = { "MW UP", "MW DN", "M6", "M7", "M8", "M9", "M10","M11","M12","M13","M14","M15","M16" };//text for buttons above 3. -MPM

#define LHX(x)      (gameStates.menus.bHires?2* (x):x)
#define LHY(y)      (gameStates.menus.bHires? (24* (y))/10:y)

const char *btype_text [] = { "BT_KEY", "BT_MOUSE_BUTTON", "BT_MOUSE_AXIS", "BT_JOY_BUTTON", "BT_JOY_AXIS", "BT_INVERT" };

#define INFO_Y 28

int m_nItems=28;
kcItem *m_items;

//----------- WARNING!!!!!!! -------------------------------------------
// THESE NEXT FOUR BLOCKS OF DATA ARE GENERATED BY PRESSING DEL+F12 WHEN
// IN THE KEYBOARD CONFIG SCREEN.  BASICALLY, THAT PROCEDURE MODIFIES THE
// U,D,L,R FIELDS OF THE ARRAYS AND DUMPS THE NEW ARRAYS INTO KCONFIG.COD
//-------------------------------------------------------------------------

tControlSettings controlSettings = {
 {
 {0xc8,0x48,0xd0,0x50,0xcb,0x4b,0xcd,0x4d,0x38,0xff,0xff,0x4f,0xff,0x51,0xff,0x4a,0xff,0x4e,0xff,0xff,0x10,0x47,0x12,0x49,0x1d,0x9d,0x39,0xff,0x21,0xff,0x1e,0xff,0x2c,0xff,0x30,0xff,0x13,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0x1f,0xff,0x33,0xff,0x34,0xff,0x23,0xff,0x14,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
 {0x5,0xc,0xff,0xff,0xff,0xff,0x7,0xf,0x13,0xb,0xff,0x6,0x8,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0x7,0xf,0x13,0xb,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x3,0x0,0x1,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
	},
 {
 {0xc8,0x48,0xd0,0x50,0xcb,0x4b,0xcd,0x4d,0x38,0xff,0xff,0x4f,0xff,0x51,0xff,0x4a,0xff,0x4e,0xff,0xff,0x10,0x47,0x12,0x49,0x1d,0x9d,0x39,0xff,0x21,0xff,0x1e,0xff,0x2c,0xff,0x30,0xff,0x13,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0x1f,0xff,0x33,0xff,0x34,0xff,0x23,0xff,0x14,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
 {0x5,0xc,0xff,0xff,0xff,0xff,0x7,0xf,0x13,0xb,0xff,0x6,0x8,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0x7,0xf,0x13,0xb,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x3,0x0,0x1,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
	},
 {
	0x2 ,0xff,0x3 ,0xff,0x4 ,0xff,0x5 ,0xff,0x6 ,0xff,0x7 ,0xff,0x8 ,0xff,0x9 ,
	0xff,0xa ,0xff,0xb ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
	},
 {
	0x2 ,0xff,0x3 ,0xff,0x4 ,0xff,0x5 ,0xff,0x6 ,0xff,0x7 ,0xff,0x8 ,0xff,0x9 ,
	0xff,0xa ,0xff,0xb ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
	}
};

kcItem kcKeyboard [] = {
 {  0, 15, 49, 71, 26, 62, 2, 63, 1,"Pitch forward", 270, BT_KEY, 255 },
 {  1, 15, 49,100, 26, 63, 3, 0, 24,"Pitch forward", 270, BT_KEY, 255 },
 {  2, 15, 57, 71, 26, 0, 4, 25, 3,"Pitch backward", 271, BT_KEY, 255 },
 {  3, 15, 57,100, 26, 1, 5, 2, 26,"Pitch backward", 271, BT_KEY, 255 },
 {  4, 15, 65, 71, 26, 2, 6, 27, 5,"Turn left", 272, BT_KEY, 255 },
 {  5, 15, 65,100, 26, 3, 7, 4, 28,"Turn left", 272, BT_KEY, 255 },
 {  6, 15, 73, 71, 26, 4, 8, 29, 7,"Turn right", 273, BT_KEY, 255 },
 {  7, 15, 73,100, 26, 5, 9, 6, 34,"Turn right", 273, BT_KEY, 255 },
 {  8, 15, 84, 71, 26, 6, 10, 35, 9,"Slide on", 274, BT_KEY, 255 },
 {  9, 15, 84,100, 26, 7, 11, 8, 36,"Slide on", 274, BT_KEY, 255 },
 { 10, 15, 92, 71, 26, 8, 12, 37, 11,"Slide left", 275, BT_KEY, 255 },
 { 11, 15, 92,100, 26, 9, 13, 10, 44,"Slide left", 275, BT_KEY, 255 },
 { 12, 15,100, 71, 26, 10, 14, 45, 13,"Slide right", 276, BT_KEY, 255 },
 { 13, 15,100,100, 26, 11, 15, 12, 30,"Slide right", 276, BT_KEY, 255 },
 { 14, 15,108, 71, 26, 12, 16, 31, 15,"Slide up", 277, BT_KEY, 255 },
 { 15, 15,108,100, 26, 13, 17, 14, 32,"Slide up", 277, BT_KEY, 255 },
 { 16, 15,116, 71, 26, 14, 18, 33, 17,"Slide down", 278, BT_KEY, 255 },
 { 17, 15,116,100, 26, 15, 19, 16, 46,"Slide down", 278, BT_KEY, 255 },
 { 18, 15,127, 71, 26, 16, 20, 47, 19,"Bank on", 279, BT_KEY, 255 },
 { 19, 15,127,100, 26, 17, 21, 18, 38,"Bank on", 279, BT_KEY, 255 },
 { 20, 15,135, 71, 26, 18, 22, 39, 21,"Bank left", 280, BT_KEY, 255 },
 { 21, 15,135,100, 26, 19, 23, 20, 40,"Bank left", 280, BT_KEY, 255 },
 { 22, 15,143, 71, 26, 20, 48, 41, 23,"Bank right", 281, BT_KEY, 255 },
 { 23, 15,143,100, 26, 21, 49, 22, 42,"Bank right", 281, BT_KEY, 255 },
 { 24,158, 49, 83, 26, 59, 26, 1, 25,"Fire primary", 282, BT_KEY, 255 },
 { 25,158, 49,112, 26, 57, 27, 24, 2,"Fire primary", 282, BT_KEY, 255 },
 { 26,158, 57, 83, 26, 24, 28, 3, 27,"Fire secondary", 283,BT_KEY, 255 },
 { 27,158, 57,112, 26, 25, 29, 26, 4,"Fire secondary", 283,BT_KEY, 255 },
 { 28,158, 65, 83, 26, 26, 34, 5, 29,"Fire flare", 284,BT_KEY, 255 },
 { 29,158, 65,112, 26, 27, 35, 28, 6,"Fire flare", 284,BT_KEY, 255 },
 { 30,158,103, 83, 26, 44, 32, 13, 31,"Accelerate", 285,BT_KEY, 255 },
 { 31,158,103,112, 26, 45, 33, 30, 14,"Accelerate", 285,BT_KEY, 255 },
 { 32,158,111, 83, 26, 30, 46, 15, 33,"reverse", 286,BT_KEY, 255 },
 { 33,158,111,112, 26, 31, 47, 32, 16,"reverse", 286,BT_KEY, 255 },
 { 34,158, 73, 83, 26, 28, 36, 7, 35,"Drop Bomb", 287,BT_KEY, 255 },
 { 35,158, 73,112, 26, 29, 37, 34, 8,"Drop Bomb", 287,BT_KEY, 255 },
 { 36,158, 84, 83, 26, 34, 44, 9, 37,"Rear View", 288,BT_KEY, 255 },
 { 37,158, 84, 112, 26, 35, 45, 36, 10,"Rear View", 288,BT_KEY, 255 },
 { 38,158,130, 83, 26, 46, 40, 19, 39,"Cruise Faster", 289,BT_KEY, 255 },
 { 39,158,130,112, 26, 47, 41, 38, 20,"Cruise Faster", 289,BT_KEY, 255 },
 { 40,158,138, 83, 26, 38, 42, 21, 41,"Cruise Slower", 290,BT_KEY, 255 },
 { 41,158,138,112, 26, 39, 43, 40, 22,"Cruise Slower", 290,BT_KEY, 255 },
 { 42,158,146, 83, 26, 40, 54, 23, 43,"Cruise Off", 291,BT_KEY, 255 },
 { 43,158,146,112, 26, 41, 55, 42, 48,"Cruise Off", 291,BT_KEY, 255 },
 { 44,158, 92, 83, 26, 36, 30, 11, 45,"Automap", 292,BT_KEY, 255 },
 { 45,158, 92,112, 26, 37, 31, 44, 12,"Automap", 292,BT_KEY, 255 },
 { 46,158,119, 83, 26, 32, 38, 17, 47,"Afterburner", 293,BT_KEY, 255 },
 { 47,158,119,112, 26, 33, 39, 46, 18,"Afterburner", 293,BT_KEY, 255 },
 { 48, 15,154, 71, 26, 22, 50, 43, 49,"Cycle Primary", 294,BT_KEY, 255 },
 { 49, 15,154,100, 26, 23, 51, 48, 54,"Cycle Primary", 294,BT_KEY, 255 },
 { 50, 15,162, 71, 26, 48, 52, 55, 51,"Cycle Second", 295,BT_KEY, 255 },
 { 51, 15,162,100, 26, 49, 53, 50, 56,"Cycle Second", 295,BT_KEY, 255 },
 { 52, 15,170, 71, 26, 50, 60, 57, 53,"Zoom In", 296,BT_KEY, 255 },
 { 53, 15,170,100, 26, 51, 61, 52, 58,"Zoom In", 296,BT_KEY, 255 },
 { 54,158,157, 83, 26, 42, 56, 49, 55,"Headlight", 297,BT_KEY, 255 },
 { 55,158,157,112, 26, 43, 57, 54, 50,"Headlight", 297,BT_KEY, 255 },
 { 56,158,165, 83, 26, 54, 58, 51, 57,"Energy->Shield", 298,BT_KEY, 255 },
 { 57,158,165,112, 26, 55, 25, 56, 52,"Energy->Shield", 298,BT_KEY, 255 },
   { 58,158,173, 83, 26, 56, 59, 53, 60,"Toggle Bomb", 299, BT_KEY,255},
   { 59,158,181, 83, 26, 58, 24, 61, 62,"Toggle Icons", 653, BT_KEY,255},
 { 60, 15,181, 71, 26, 52, 62, 58, 61,"Use Cloak", 751,BT_KEY, 255 },
 { 61, 15,181,100, 26, 53, 63, 60, 59,"Use Cloak", 751,BT_KEY, 255 },
 { 62, 15,189, 71, 26, 60, 0, 59, 63,"Use Invul", 752,BT_KEY, 255 },
 { 63, 15,189,100, 26, 61, 1, 62, 0,"Use Invul", 752,BT_KEY, 255 },
   { 64,158,189, 83, 26, 58, 24, 61, 62,"Slowmo/Speed", 910, BT_KEY,255 },
   { 65,158,189,112, 26, 58, 24, 61, 62,"Slowmo/Speed", 910, BT_KEY,255 }
};

ubyte kcKbdFlags [MAX_CONTROLS];

kcItem kcJoystick [] = {
 {  0, 15, 46, 71, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 {  1, 15, 54, 71, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 {  2, 15, 94, 71, 26, 35, 3, 10, 11,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 {  3, 15,102, 71, 26, 2, 25, 11, 12,"reverse", 286, BT_JOY_BUTTON, 255 },
 {  4, 15, 62, 71, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 {  5,158, 46, 71, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 {  6,158, 54, 71, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 {  7,158, 62, 71, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 {  8,158, 70, 71, 26, 7, 9, 26, 34,"Slide up", 277, BT_JOY_BUTTON, 255 },
 {  9,158, 78, 71, 26, 8, 10, 34, 35,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 10,158, 86, 71, 26, 9, 11, 35, 2,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 11,158, 94, 71, 26, 10, 12, 2, 3,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 12,158,102, 71, 26, 11, 28, 3, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 13, 15,162, 51, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 15, 15,170, 51, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 17,158,162, 58, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 19,158,170, 58, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 21,158,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 23,158,186, 58, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 25, 15,110, 71, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 26, 15, 70, 71, 26, 4, 34, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 27, 15,118, 71, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 28,158,110, 71, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 29,158,118, 71, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 30, 15,126, 71, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 31,158,126, 71, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 32,158,134, 71, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 33, 15,134, 71, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
 { 34, 15, 78, 71, 26, 26, 35, 8,  9,"Use Cloak", 751, BT_JOY_BUTTON, 255 },
 { 35, 15, 86, 71, 26, 34, 2, 9, 10,"Use Invul", 752, BT_JOY_BUTTON, 255 },

 { 36, 15, 46, 100, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 { 37, 15, 54, 100, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 { 38, 15, 94, 100, 26, 35, 3, 10, 11,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 { 39, 15,102, 100, 26, 2, 25, 11, 12,"reverse", 286, BT_JOY_BUTTON, 255 },
 { 40, 15, 62, 100, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 { 41,158, 46, 100, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 { 42,158, 54, 100, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 { 43,158, 62, 100, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 { 44,158, 70, 100, 26, 7, 9, 26, 34,"Slide up", 277, BT_JOY_BUTTON, 255 },
 { 45,158, 78, 100, 26, 8, 10, 34, 35,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 46,158, 86, 100, 26, 9, 11, 35, 2,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 47,158, 94, 100, 26, 10, 12, 2, 3,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 48,158,102, 100, 26, 11, 28, 3, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 49, 15,162, 80, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 50, 15,170, 80, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 51,158,162, 87, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 52,158,170, 87, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 53,158,178, 87, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 54,158,186, 87, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 55, 15,110, 100, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 56, 15, 70, 100, 26, 4, 34, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 57, 15,118, 100, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 58,158,110, 100, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 59,158,118, 100, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 60, 15,126, 100, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 61,158,126, 100, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 62,158,134, 100, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 63, 15,134, 100, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
 { 64, 15, 78, 100, 26, 26, 35, 8,  9,"Use Cloak", 751, BT_JOY_BUTTON, 255 },
 { 65, 15, 86, 100, 26, 34, 2, 9, 10,"Use Invul", 752, BT_JOY_BUTTON, 255 },

 { 14, 15,162,115, 8, 33, 16, 13, 17,"Pitch U/D", 300, BT_INVERT, 255 },
 { 16, 15,170,115, 8, 14, 17, 15, 19,"Turn L/R", 301, BT_INVERT, 255 },
 { 18,158,162,123, 8, 32, 20, 17, 15,"Slide L/R", 302, BT_INVERT, 255 },
 { 20,158,170,123, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 22,158,178,123, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 24,158,186,123, 8, 22, 13, 23, 0,"throttle", 305, BT_INVERT, 255 }

};

kcItem kcMouse [] = {
 {  0, 25, 46, 85, 26, 23, 1, 24, 5,"Fire primary", 282, BT_MOUSE_BUTTON, 255 },
 {  1, 25, 54, 85, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_MOUSE_BUTTON, 255 },
 {  2, 25, 78, 85, 26, 26, 3, 8, 9,"Accelerate", 285, BT_MOUSE_BUTTON, 255 },
 {  3, 25, 86, 85, 26, 2, 27, 9, 10,"reverse", 286, BT_MOUSE_BUTTON, 255 },
 {  4, 25, 62, 85, 26, 1, 26, 6, 7,"Fire flare", 284, BT_MOUSE_BUTTON, 255 },
 {  5,180, 46, 59, 26, 24, 6, 0, 1,"Slide on", 274, BT_MOUSE_BUTTON, 255 },
 {  6,180, 54, 59, 26, 5, 7, 1, 4,"Slide left", 275, BT_MOUSE_BUTTON, 255 },
 {  7,180, 62, 59, 26, 6, 8, 4, 26,"Slide right", 276, BT_MOUSE_BUTTON, 255 },
 {  8,180, 70, 59, 26, 7, 9, 26, 2,"Slide up", 277, BT_MOUSE_BUTTON, 255 },
 {  9,180, 78, 59, 26, 8, 10, 2, 3,"Slide down", 278, BT_MOUSE_BUTTON, 255 },
 { 10,180, 86, 59, 26, 9, 11, 3, 27,"Bank on", 279, BT_MOUSE_BUTTON, 255 },
 { 11,180, 94, 59, 26, 10, 12, 27, 25,"Bank left", 280, BT_MOUSE_BUTTON, 255 },
 { 12,180,102, 59, 26, 11, 30, 25, 28,"Bank right", 281, BT_MOUSE_BUTTON, 255 },

 { 13,103,146, 58, 26, 29, 15, 30, 14,"Pitch U/D", 300, BT_MOUSE_AXIS, 255 },
 { 14,103,146,106, 8, 23, 16, 13, 15,"Pitch U/D", 300, BT_INVERT, 255 },
 { 15,103,154, 58, 26, 13, 17, 14, 16,"Turn L/R", 301, BT_MOUSE_AXIS, 255 },
 { 16,103,154,106, 8, 14, 18, 15, 17,"Turn L/R", 301, BT_INVERT, 255 },
 { 17,103,162, 58, 26, 15, 19, 16, 18,"Slide L/R", 302, BT_MOUSE_AXIS, 255 },
 { 18,103,162,106, 8, 16, 20, 17, 19,"Slide L/R", 302, BT_INVERT, 255 },
 { 19,103,170, 58, 26, 17, 21, 18, 20,"Slide U/D", 303, BT_MOUSE_AXIS, 255 },
 { 20,103,170,106, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 21,103,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_MOUSE_AXIS, 255 },
 { 22,103,178,106, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 23,103,186, 58, 26, 21, 0, 22, 24,"Throttle", 305, BT_MOUSE_AXIS, 255 },
 { 24,103,186,106, 8, 22, 5, 23, 0,"Throttle", 305, BT_INVERT, 255 },

 { 25, 25,102, 85, 26, 27, 28, 11, 12,"Rear View", 288, BT_MOUSE_BUTTON, 255 },
 { 26, 25, 70, 85, 26, 4, 2, 7, 8,"Drop Bomb", 287, BT_MOUSE_BUTTON, 255 },
 { 27, 25, 94, 85, 26, 3, 25, 10, 11,"Afterburner", 293, BT_MOUSE_BUTTON, 255 },
 { 28, 25,110, 85, 26, 25, 29, 12, 29,"Cycle Primary", 294, BT_MOUSE_BUTTON, 255 },
 { 29, 25,118, 85, 26, 28, 13, 28, 30,"Cycle Second", 295, BT_MOUSE_BUTTON, 255 },
 { 30,180,118, 59, 26, 12, 14, 29, 13,"Zoom in", 296, BT_MOUSE_BUTTON, 255 }
};

kcItem kcSuperJoy [] = {
 {  0, 25, 46, 85, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 {  1, 25, 54, 85, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 {  2, 25, 85, 85, 26, 26, 3, 9, 10,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 {  3, 25, 93, 85, 26, 2, 25, 10, 11,"reverse", 286, BT_JOY_BUTTON, 255 },
 {  4, 25, 62, 85, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 {  5,180, 46, 79, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 {  6,180, 54, 79, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 {  7,180, 62, 79, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 {  8,180, 70, 79, 26, 7, 9, 26, 9,"Slide up", 277, BT_JOY_BUTTON, 255 },
 {  9,180, 78, 79, 26, 8, 10, 8, 2,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 10,180, 86, 79, 26, 9, 11, 2, 3,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 11,180, 94, 79, 26, 10, 12, 3, 12,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 12,180,102, 79, 26, 11, 28, 11, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 13, 22,162, 51, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 14, 22,162, 99, 8, 33, 16, 13, 17,"Pitch U/D", 300, BT_INVERT, 255 },
 { 15, 22,170, 51, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 16, 22,170, 99, 8, 14, 17, 15, 19,"Turn L/R", 301, BT_INVERT, 255 },
 { 17,164,162, 58, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 18,164,162,106, 8, 32, 20, 17, 15,"Slide L/R", 302, BT_INVERT, 255 },
 { 19,164,170, 58, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 20,164,170,106, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 21,164,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 22,164,178,106, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 23,164,186, 58, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 24,164,186,106, 8, 22, 13, 23, 0,"throttle", 305, BT_INVERT, 255 },
 { 25, 25,110, 85, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 26, 25, 70, 85, 26, 4, 2, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 27, 25,118, 85, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 28,180,110, 79, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 29,180,118, 79, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 30, 25,126, 85, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 31,180,126, 79, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 32,180,134, 79, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 33, 25,134, 85, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
};

#ifdef D2X_KEYS
//added on 2/4/99 by Victor Rachels to add d1x new keys
kcItem kcHotkeys [] = {
//        id,x,y,w1,w2,u,d,l,r,text_num1,nType,value
 {  0, 15, 49, 71, 26, 27, 2, 27, 1, "Weapon 1", 306, BT_KEY, 255 },
 {  1, 15, 49,100, 26, 26, 3, 0, 2, "Weapon 1", 306, BT_JOY_BUTTON, 255 },
 {  2, 15, 57, 71, 26, 0, 4, 1, 3, "Weapon 2", 307, BT_KEY, 255 },
 {  3, 15, 57,100, 26, 1, 5, 2, 4, "Weapon 2", 307, BT_JOY_BUTTON, 255 },
 {  4, 15, 65, 71, 26, 2, 6, 3, 5, "Weapon 3", 308, BT_KEY, 255 },
 {  5, 15, 65,100, 26, 3, 7, 4, 6, "Weapon 3", 308, BT_JOY_BUTTON, 255 },
 {  6, 15, 73, 71, 26, 4, 8, 5, 7, "Weapon 4", 309, BT_KEY, 255 },
 {  7, 15, 73,100, 26, 5, 9, 6, 8, "Weapon 4", 309, BT_JOY_BUTTON, 255 },
 {  8, 15, 81, 71, 26, 6, 10, 7, 9, "Weapon 5", 310, BT_KEY, 255 },
 {  9, 15, 81,100, 26, 7, 11, 8, 10, "Weapon 5", 310, BT_JOY_BUTTON, 255 },

 { 10, 15, 89, 71, 26, 8, 12, 9, 11, "Weapon 6", 311, BT_KEY, 255 },
 { 11, 15, 89,100, 26, 9, 13, 10, 12, "Weapon 6", 311, BT_JOY_BUTTON, 255 },
 { 12, 15, 97, 71, 26, 10, 14, 11, 13, "Weapon 7", 312, BT_KEY, 255 },
 { 13, 15, 97,100, 26, 11, 15, 12, 14, "Weapon 7", 312, BT_JOY_BUTTON, 255 },
 { 14, 15,105, 71, 26, 12, 16, 13, 15, "Weapon 8", 313, BT_KEY, 255 },
 { 15, 15,105,100, 26, 13, 17, 14, 16, "Weapon 8", 313, BT_JOY_BUTTON, 255 },
 { 16, 15,113, 71, 26, 14, 18, 15, 17, "Weapon 9", 314, BT_KEY, 255 },
 { 17, 15,113,100, 26, 15, 19, 16, 18, "Weapon 9", 314, BT_JOY_BUTTON, 255 },
 { 18, 15,121, 71, 26, 16, 20, 17, 19, "Weapon 10", 315, BT_KEY, 255 },
 { 19, 15,121,100, 26, 17, 21, 18, 20, "Weapon 10", 315, BT_JOY_BUTTON, 255 }

	//{ 20, 15,131, 71, 26, 18, 22, 19, 21, "CYC PRIMARY", BT_KEY, 255 },
	//{ 21, 15,131,100, 26, 19, 23, 20, 22, "CYC PRIMARY", BT_JOY_BUTTON, 255 },
	//{ 22, 15,139, 71, 26, 20, 24, 21, 23, "CYC SECONDARY", BT_KEY, 255 },
	//{ 23, 15,139,100, 26, 21, 25, 22, 24, "CYC SECONDARY", BT_JOY_BUTTON, 255 },
	//{ 24, 8,147, 78, 26, 22, 26, 23, 25, "TOGGLE_PRIM AUTO", BT_KEY, 255 },
	//{ 25, 8,147,107, 26, 23, 27, 24, 26, "TOGGLE_PRIM_AUTO", BT_JOY_BUTTON, 255 },
	//{ 26, 8,155, 78, 26, 24, 1, 25, 27, "TOGGLE SEC AUTO", BT_KEY, 255 },
	//{ 27, 8,155,107, 26, 25, 0, 26, 0, "TOGGLE SEC AUTO", BT_JOY_BUTTON, 255 },
};
//end this section addition - VR
#endif

CExternalControls externalControls;

CFixVector ExtForceVec;
CFixMatrix ExtApplyForceMatrix;

int ExtJoltInfo [3]={0,0,0};
int ExtXVibrateInfo [2]={0,0};
int ExtYVibrateInfo [2]={0,0};
ubyte ExtXVibrateClear=0;
ubyte ExtYVibrateClear=0;

int CControlConfig::m_startAxis [JOY_MAX_AXES];

CControlConfig controlConfig;

//------------------------------------------------------------------------------

int CControlConfig::IsAxisUsed (int axis)
{
for (int i = 0; i < NUM_JOY_CONTROLS; i++) {
	if ((kcJoystick [i].nType == BT_JOY_AXIS) && (kcJoystick [i].value == axis))
		return 1;
	}
return 0;
}

//------------------------------------------------------------------------------

int CControlConfig::FindItemAt (int x, int y)
{
for (int i = 0; i < m_nItems; i++) {
	if (((m_items [i].x + m_items [i].w1) == x) && (m_items [i].y == y))
		return i;
	}
return -1;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemRight (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
nCurItem = ref [nCurItem];
return pos [(nCurItem + 1) % nItems].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemLeft (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
nCurItem = ref [nCurItem];
return pos [nCurItem ? nCurItem - 1 : nItems - 1].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemUp (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
	int l, r, x, y, yStart, h, i, j, dx, dy, dMin;

h = 0;
i = j = ref [nCurItem];
l = pos [i].l;
r = pos [i].r;
x = (l + r) / 2;
y = yStart = pos [i].y;
#if 0
do {
	if (--i < 0)
		i = m_nItems - 1;
	if ((r >= pos [i].l) && (l <= pos [i].r))
		return pos [i].i;
	} while (i != j);
#endif
dMin = 0x7fffffff;
dy = 0;
for (;;) {
	if (--i < 0)
		i = nItems - 1;
	if (i == j)
		break;
	if (pos [i].y == yStart)
		continue;
	dx = abs (x - (pos [i].l + pos [i].r) / 2);
	if (y != pos [i].y) {
		y = pos [i].y;
		dy += 10;
		}
	dx += dy;
	if (dMin > dx) {
		dMin = dx;
		h = i;
		}
	}
return pos [h].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemDown (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
	int l, r, x, y, yStart, h, i, j, dx, dy, dMin;

h = 0;
i = j = ref [nCurItem];
l = pos [i].l;
r = pos [i].r;
x = (l + r) / 2;
y = yStart = pos [i].y;
#if 0
do {
	i = (i + 1) % m_nItems;
	if ((r >= pos [i].l) && (l <= pos [i].r))
		return pos [i].i;
	} while (i != j);
#endif
dMin = 0x7fffffff;
dy = 0;
for (;;) {
	i = (i + 1) % nItems;
	if (i == j)
		break;
	if (pos [i].y == yStart)
		continue;
	dx = abs (x - (pos [i].l + pos [i].r) / 2);
	if (y != pos [i].y) {
		y = pos [i].y;
		dy += 10;
		}
	dx += dy;
	if (dMin > dx) {
		dMin = dx;
		h = i;
		}
	}
return pos [h].i;
}

//------------------------------------------------------------------------------

const char* CControlConfig::MouseButtonText (int i)
{
if (i < 0)
	return "";
if (i < 3)
	return baseGameTexts [mouseButtonTextIndex [i]][0];
if (i - 3 < (int) sizeofa (extraMouseButtonTextIndex))
	return extraMouseButtonTextIndex [i - 3];
return "";
}

//------------------------------------------------------------------------------

const char* CControlConfig::MouseAxisText (int i)
{
if (i < 0)
	return "";
if (i < (int) sizeofa (mouseAxisTextIndex))
	return baseGameTexts [mouseAxisTextIndex [i]][0];
return "";
}

//------------------------------------------------------------------------------

const char* CControlConfig::YesNoText (int i)
{
return baseGameTexts [yesNoTextIndex [i != 0]][0];
}

//------------------------------------------------------------------------------

int CControlConfig::GetItemHeight (kcItem *item)
{
	int w, h, aw;
	char szText [10];

if (item->value == 255)
	strcpy (szText, "");
else {
	switch (item->nType) {
		case BT_KEY:
			strncpy (szText, (size_t (item->value) < sizeofa (pszKeyText)) ? pszKeyText [item->value] : "", sizeof (szText));
			break;

		case BT_MOUSE_BUTTON:
			strncpy (szText, MouseButtonText (item->value), sizeof (szText));
			break;

		case BT_MOUSE_AXIS:
			strncpy (szText, MouseAxisText (item->value), sizeof (szText));
			break;

		case BT_JOY_BUTTON:
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d B%d", j_button [item->value].joydev,
					  j_Get_joydev_button_number (item->value);
#else
		 {
				int	nStick = item->value / MAX_BUTTONS_PER_JOYSTICK;
				int	nBtn = item->value % MAX_BUTTONS_PER_JOYSTICK;
				int	nHat = sdlJoysticks [nStick].nButtons;
				//static char szHatDirs [4] = {'U', 'L', 'D', 'R'};
				static char cHatDirs [4] = { (char) 130, (char) 127, (char) 128, (char) 129};

			if (nBtn < nHat)
				sprintf (szText, "J%d B%d", nStick + 1, nBtn + 1);
			else
				sprintf (szText, "HAT%d%c", nStick + 1, cHatDirs [nBtn - nHat]);
			}
#endif
			break;

		case BT_JOY_AXIS:
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d A%d", j_axis [item->value].joydev,
					  j_Get_joydev_axis_number (item->value);
#else
		 {
				int	nStick = item->value / MAX_AXES_PER_JOYSTICK;
				int	nAxis = item->value % MAX_AXES_PER_JOYSTICK;
				static char	cAxis [4] = {'X', 'Y', 'Z', 'R'};

			if (nAxis < 4)
				sprintf (szText, "J%d %c", nStick + 1, cAxis [nAxis]);
			else
				sprintf (szText, "J%d A%d", nStick + 1, nAxis + 1);
			}
#endif
			break;

		case BT_INVERT:
			strncpy (szText, YesNoText (item->value), sizeof (szText));
			break;
		}
	}
fontManager.Current ()->StringSize (szText, w, h, aw);
return h;
}

//------------------------------------------------------------------------------

#define kc_gr_pixel(_x,_y)		DrawPixelClipped ((_x), (_y))
#define KC_LHX(_x) 				(LHX (_x)+m_xOffs)
#define KC_LHY(_y) 				(LHY (_y)+m_yOffs)

void CControlConfig::DrawTitle (void)
{
	char szTitle [200];
	const char *p = strchr (m_pszTitle, '\n');

if (p) {
	int l = (int) (p - m_pszTitle);
	if (l >= (int) sizeof (szTitle))
		l = (int) sizeof (szTitle) - 1;
	memcpy (szTitle, m_pszTitle, l);
	szTitle [l] = '\0';
	p = szTitle;
	}
fontManager.SetCurrent (MEDIUM3_FONT);
GrString (0x8000, KC_LHY (8), p, NULL);
}

//------------------------------------------------------------------------------

void CControlConfig::DrawItem (kcItem *item, int is_current, int bRedraw)
{
	static char cHatDirs [4] = { (char) 130, (char) 127, (char) 128, (char) 129};
	static char	cAxis [4] = {'X', 'Y', 'Z', 'R'};

	int x, w, h, aw;
	char szText [64];

if (bRedraw)
	return;

if (is_current)
	fontManager.SetColorRGBi (RGBA_PAL2 (20,20,29), 1, 0, 0);
else
	fontManager.SetColorRGBi (RGBA_PAL2 (15,15,24), 1, 0, 0);
GrString (KC_LHX (item->x), KC_LHY (item->y), item->textId ? GT (item->textId) : item->text, NULL);

*szText = '\0';
if (item->value != 255) {
	switch (item->nType) {
		case BT_KEY:
			if (size_t (item->value) < sizeofa (pszKeyText))
				strncat (szText, pszKeyText [item->value], 10);
			break;

		case BT_MOUSE_BUTTON:
			//strncpy (szText, baseGameTexts [mouseButtonTextIndex [item->value]], 10); break;
			strncpy (szText, MouseButtonText (item->value), 10);
			break;

		case BT_MOUSE_AXIS:
			strncpy (szText, MouseAxisText (item->value), 10);
			break;

		case BT_JOY_BUTTON: {
#ifdef USE_LINUX_JOY
			sprintf (szText, "J%d B%d",
					  j_button [item->value].joydev, j_Get_joydev_button_number (item->value);
#else
				int	nStick = item->value / MAX_BUTTONS_PER_JOYSTICK;
				int	nBtn = item->value % MAX_BUTTONS_PER_JOYSTICK;
				int	nHat = sdlJoysticks [nStick].nButtons;
				//static char szHatDirs [4] = {'U', 'L', 'D', 'R'};
			if (nBtn < nHat)
				sprintf (szText, "J%d B%d", nStick + 1, nBtn + 1);
			else
				sprintf (szText, "HAT%d%c", nStick + 1, cHatDirs [nBtn - nHat]);
#endif
			}
			break;

		case BT_JOY_AXIS: {
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d A%d", j_axis [item->value].joydev, j_Get_joydev_axis_number (item->value));
#elif 1//defined (_WIN32)
				int	nStick = item->value / MAX_AXES_PER_JOYSTICK;
				int	nAxis = item->value % MAX_AXES_PER_JOYSTICK;

			if (nAxis < 4)
				sprintf (szText, "J%d %c", nStick + 1, cAxis [nAxis]);
			else
				sprintf (szText, "J%d A%d", nStick + 1, nAxis + 1);
#else
			strncpy (szText, baseGameTexts [JOYAXIS_TEXT (item->value)], 10);
#endif
			}
			break;

		case BT_INVERT:
			strncpy (szText, YesNoText (item->value), 10);
			break;
		}
	}

if (item->w1) {
	fontManager.Current ()->StringSize (szText, w, h, aw);

	if (is_current)
		CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21, 0, 24));
	else
		CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (16, 0, 19));
	OglDrawFilledRect (KC_LHX (item->x + item->w1), KC_LHY (item->y - 1),
				KC_LHX (item->x + item->w1 + item->w2), KC_LHY (item->y) + h);
	fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);
	x = LHX (item->w1 + item->x) + ((LHX (item->w2) - w) / 2) + m_xOffs;
	GrString (x, KC_LHY (item->y), szText, NULL);
	}
}

//------------------------------------------------------------------------------

void CControlConfig::DrawHeader (void)
{
fontManager.SetCurrent (GAME_FONT);
fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);

GrString (0x8000, KC_LHY (20), TXT_KCONFIG_STRING_1, NULL);
fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);
if (m_items == kcKeyboard) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31, 27, 6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));
	OglDrawLine (KC_LHX (98), KC_LHY (42), KC_LHX (106), KC_LHY (42));
	OglDrawLine (KC_LHX (120), KC_LHY (42), KC_LHX (128), KC_LHY (42));
	kc_gr_pixel (KC_LHX (98), KC_LHY (43));
	kc_gr_pixel (KC_LHX (98), KC_LHY (44));
	kc_gr_pixel (KC_LHX (128), KC_LHY (43));
	kc_gr_pixel (KC_LHX (128), KC_LHY (44));

	GrString (KC_LHX (109), KC_LHY (40), "OR", NULL);

	OglDrawLine (KC_LHX (253), KC_LHY (42), KC_LHX (261), KC_LHY (42));
	OglDrawLine (KC_LHX (274), KC_LHY (42), KC_LHX (283), KC_LHY (42));
	kc_gr_pixel (KC_LHX (253), KC_LHY (43));
	kc_gr_pixel (KC_LHX (253), KC_LHY (44));
	kc_gr_pixel (KC_LHX (283), KC_LHY (43));
	kc_gr_pixel (KC_LHX (283), KC_LHY (44));

	GrString (KC_LHX (264), KC_LHY (40), "OR", NULL);

}
if (m_items == kcJoystick) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));
	OglDrawLine (KC_LHX (18), KC_LHY (37), KC_LHX (135), KC_LHY (37));
	OglDrawLine (KC_LHX (181), KC_LHY (37), KC_LHX (294), KC_LHY (37));
	OglDrawLine (KC_LHX (18), KC_LHY (119+18), KC_LHX (144), KC_LHY (119+18));
	OglDrawLine (KC_LHX (174), KC_LHY (119+18), KC_LHX (294), KC_LHY (119+18));
	GrString (0x8000, KC_LHY (35), TXT_BUTTONS_HATS, NULL);
	GrString (0x8000,KC_LHY (125+18), TXT_AXES, NULL);
	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (KC_LHX (85), KC_LHY (145+8), TXT_AXIS, NULL);
	GrString (KC_LHX (120), KC_LHY (145+8), TXT_INVERT, NULL);
	GrString (KC_LHX (235), KC_LHY (145+8), TXT_AXIS, NULL);
	GrString (KC_LHX (270), KC_LHY (145+8), TXT_INVERT, NULL);
} else if (m_items == kcMouse) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31,27,6));
	OglDrawLine (KC_LHX (18), KC_LHY (37), KC_LHX (135), KC_LHY (37));
	OglDrawLine (KC_LHX (181), KC_LHY (37), KC_LHX (294), KC_LHY (37));
	OglDrawLine (KC_LHX (18), KC_LHY (119+5), KC_LHX (144), KC_LHY (119+5));
	OglDrawLine (KC_LHX (174), KC_LHY (119+5), KC_LHX (294), KC_LHY (119+5));
	GrString (0x8000, KC_LHY (35), TXT_BUTTONS, NULL);
	GrString (0x8000,KC_LHY (125+5), TXT_AXES, NULL);
	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (KC_LHX (169), KC_LHY (137), TXT_AXIS, NULL);
	GrString (KC_LHX (199), KC_LHY (137), TXT_INVERT, NULL);
}
#ifdef D2X_KEYS
else if (m_items == kcHotkeys)
{
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));

	GrString (KC_LHX (94), KC_LHY (40), "KB", NULL);
	GrString (KC_LHX (121), KC_LHY (40), "JOY", NULL);
}
#endif
}

//------------------------------------------------------------------------------

void CControlConfig::DrawTable (void)
{
	int	i;

for (i = 0; i < m_nItems; i++)
	DrawItem (m_items + i, 0, 0);
DrawItem (m_items + m_nCurItem, 1, 0);
}

//------------------------------------------------------------------------------

void CControlConfig::DrawScreen (void)
{
m_bRedraw = 1;
if (gameOpts->menus.nStyle && gameStates.app.bGameRunning)
	GameRenderFrame ();
CCanvas::SetCurrent (backgroundManager.Canvas ());
backgroundManager.Redraw ();
CCanvas::SetCurrent (NULL);
DrawTitle ();
m_closeX = m_closeY = gameStates.menus.bHires ? 15 : 7;
m_closeX += m_xOffs;
m_closeY += m_yOffs;
m_closeSize = gameStates.menus.bHires?10:5;
CCanvas::Current ()->SetColorRGB (0, 0, 0, 255);
OglDrawFilledRect (m_closeX, m_closeY, m_closeX + m_closeSize, m_closeY + m_closeSize);
CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21, 21, 21));
OglDrawFilledRect (m_closeX + LHX (1), m_closeY + LHX (1), m_closeX + m_closeSize - LHX (1), m_closeY + m_closeSize - LHX (1));
DrawHeader ();
DrawTable ();
SDL_ShowCursor (0);
}

//------------------------------------------------------------------------------

void CControlConfig::DrawQuestion (kcItem *item)
{
	static int looper = 0;

	int x, w, h, aw;

fontManager.Current ()->StringSize ("?", w, h, aw);
CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21*fades [looper]/31, 0, 24*fades [looper]/31));
if (++looper>63)
	looper=0;
OglDrawFilledRect (KC_LHX (item->w1 + item->x), KC_LHY (item->y - 1),
						 KC_LHX (item->w1 + item->x + item->w2), KC_LHY (item->y) + h);
fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
x = LHX (item->w1+item->x)+ ((LHX (item->w2)-w)/2)+m_xOffs;
GrString (x, KC_LHY (item->y), "?", NULL);
if (ogl.m_states.nDrawBuffer != GL_BACK)
	GrUpdate (1);
}

//------------------------------------------------------------------------------

void CControlConfig::Quit (void)
{
CCanvas::Pop ();
//bg->menu_canvas = NULL;
GameFlushInputs ();
backgroundManager.Remove ();
SDL_ShowCursor (0);
if (m_bTimeStopped)
	StartTime (0);
gameStates.menus.nInMenu--;
paletteManager.SetEffect (0, 0, 0);
}

//------------------------------------------------------------------------------

int CControlConfig::AssignControl (kcItem *item, int nType, ubyte code)
{
	int	i, n;

if (code == 255)
	return nType;

for (i = 0, n = (int) (item - m_items); i < m_nItems; i++) {
	if ((i != n) && (m_items [i].nType == nType) && (m_items [i].value == code)) {
		m_items [i].value = 255;
		if (ogl.m_states.nDrawBuffer == GL_FRONT)
			DrawItem (m_items + i, 0);
		}
	}
item->value = code;
if (ogl.m_states.nDrawBuffer == GL_FRONT) {
	DrawItem (item, 1);
	backgroundManager.Restore (m_xOffs, m_yOffs, KC_LHX (310), CCanvas::Current ()->Font ()->Height (), 0, KC_LHY (INFO_Y));
	}
GameFlushInputs ();
fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 1);
return BT_NONE;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::KeyCtrlFunc (void)
{
	int	i, n, f;

for (i = 0; i < 256; i++) {
	if (gameStates.input.keys.pressed [i] && strlen (pszKeyText [i])) {
		f = 0;
		for (n = 0; n < (int) sizeof (system_keys); n++)
			if (system_keys [n] == i)
				f = 1;
		if (!f)
			return (ubyte) i;
		}
	}
return 255;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::JoyBtnCtrlFunc (void)
{
	int	i;
	ubyte code = 255;

if (gameStates.input.nJoyType == CONTROL_THRUSTMASTER_FCS) {
	int axis [JOY_MAX_AXES];
	JoyReadRawAxis (JOY_ALL_AXIS, axis);
	ControlsReadFCS (axis [3]);
	if (JoyGetButtonState (19))
		code = 19;
	else if (JoyGetButtonState (15))
		code = 15;
	else if (JoyGetButtonState (11))
		code = 11;
	else if (JoyGetButtonState (7))
		code = 7;
	for (i = 0; i < 4; i++)
		if (JoyGetButtonState (i))
			return (ubyte) i;
	}
else if (gameStates.input.nJoyType == CONTROL_FLIGHTSTICK_PRO) {
	for (i = 4; i < 20; i++) {
		if (JoyGetButtonState (i))
			return (ubyte) i;
		}
	}
else {
	for (i = 0; i < JOY_MAX_BUTTONS; i++) {
		if (JoyGetButtonState (i))
			return (ubyte) i;
		}
	}
return code;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::MouseBtnCtrlFunc (void)
{
int i, b = MouseGetButtons ();
for (i = 0; i < 16; i++)
	if (b & (1 << i))
		return (ubyte) i;
return 255;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::JoyAxisCtrlFunc (void)
{
	int curAxis [JOY_MAX_AXES];
	int i, hd, dd;
	int bLinJoySensSave = gameOpts->input.joystick.bLinearSens;
	ubyte code = 255;

memset (curAxis, 0, sizeof (curAxis));
gameOpts->input.joystick.bLinearSens = 1;
gameStates.input.kcPollTime = 128;
ControlsReadJoystick (curAxis);
gameOpts->input.joystick.bLinearSens = bLinJoySensSave;
for (i = dd = 0; i < JOY_MAX_AXES; i++) {
	hd = abs (curAxis [i] - m_startAxis [i]);
  	if ((hd > (128 * 3 / 4)) && (hd > dd)) {
		dd = hd;
		code = i;
		m_startAxis [i] = curAxis [i];
		}
	}
return code;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::MouseAxisCtrlFunc (void)
{
	int dx, dy;
#ifdef SDL_INPUT
	int dz;
#endif
	ubyte code = 255;

#ifdef SDL_INPUT
MouseGetDeltaZ (&dx, &dy, &dz);
#else
MouseGetDelta (&dx, &dy);
#endif
console.printf (CON_VERBOSE, "mouse: %3d %3d\n", dx, dy);
dx = abs (dx);
dy = abs (dy);
if (max (dx, dy) > 20) {
	code = dy > dx;
	}
#ifdef SDL_INPUT
dz = abs (dz);
if ((dz > 20) && (dz > code ? dy : dx))
	code = 2;
#endif
return code;
}

//------------------------------------------------------------------------------

int CControlConfig::ChangeControl (kcItem *item, int nType, kc_ctrlfunc_ptr ctrlfunc, const char *pszMsg)
{
	int k = 255;

	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (0x8000, KC_LHY (INFO_Y), pszMsg, NULL);
{
	if ((gameData.app.nGameMode & GM_MULTI) && (gameStates.app.nFunctionMode == FMODE_GAME) && (!gameStates.app.bEndLevelSequence))
		MultiMenuPoll ();
//		if (gameData.app.nGameMode & GM_MULTI)
//			GameFrame (0, 0);				// Continue
	k = KeyInKey ();
	if (k == KEY_ESC)
		return AssignControl (item, BT_NONE, 255);
	if (k == KEY_PRINT_SCREEN) {
		SaveScreenShot (NULL, 0);
		return AssignControl (item, BT_NONE, 255);
		}
	if (ogl.m_states.nDrawBuffer == GL_FRONT)
		G3_SLEEP (10);
	DrawQuestion (item);
	}
return AssignControl (item, nType, ctrlfunc ());
}

//------------------------------------------------------------------------------

int CControlConfig::ChangeInvert (kcItem * item)
{
GameFlushInputs ();
item->value = !item->value;
if (ogl.m_states.nDrawBuffer == GL_FRONT)
	DrawItem (item, 1);
return BT_NONE;
}

//------------------------------------------------------------------------------

void CControlConfig::QSortItemPos (tItemPos *pos, int left, int right)
{
	int			l = left,
					r = right;
	tItemPos	h, m = pos [(l + r) / 2];

do {
	while ((pos [l].y < m.y) || ((pos [l].y == m.y) && (pos [l].l < m.l)))
		l++;
	while ((pos [r].y > m.y) || ((pos [r].y == m.y) && (pos [r].l > m.l)))
		r--;
	if (l <= r) {
		if (l < r) {
			h = pos [l];
			pos [l] = pos [r];
			pos [r] = h;
			}
		l++;
		r--;
		}
	} while (l <= r);
if (l < right)
	QSortItemPos (pos, l, right);
if (left < r)
	QSortItemPos (pos, left, r);
}

//------------------------------------------------------------------------------

CControlConfig::tItemPos* CControlConfig::GetItemPos (kcItem* items, int nItems)
{
	tItemPos	*pos;
	int			i;

if (!(pos = new tItemPos [nItems]))
	return NULL;
for (i = 0; i < nItems; i++) {
	pos [i].l = items [i].x + items [i].w1;
	pos [i].r = pos [i].l + items [i].w2;
	pos [i].y = items [i].y;
	pos [i].i = i;
	}
QSortItemPos (pos, 0, nItems - 1);
return pos;
}

//------------------------------------------------------------------------------

int* CControlConfig::GetItemRef (int nItems, tItemPos* pos)
{
	int	*ref;
	int	i;

if (!(ref = new int [nItems]))
	return NULL;
for (i = 0; i < nItems; i++)
	ref [pos [i].i] = i;
return ref;
}

//------------------------------------------------------------------------------

void CControlConfig::LinkKbdEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcKeyboard, NUM_KEY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_KEY_CONTROLS, pos))) {
		for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++) {
			kcKeyboard [i].u = FindNextItemUp (j, i, pos, ref);
			kcKeyboard [i].d = FindNextItemDown (j, i, pos, ref);
			kcKeyboard [i].l = FindNextItemLeft (j, i, pos, ref);
			kcKeyboard [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkJoyEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcJoystick, NUM_JOY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_JOY_CONTROLS, pos))) {
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
			kcJoystick [i].u = FindNextItemUp (j, i, pos, ref);
			kcJoystick [i].d = FindNextItemDown (j, i, pos, ref);
			kcJoystick [i].l = FindNextItemLeft (j, i, pos, ref);
			kcJoystick [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkMouseEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcMouse, NUM_MOUSE_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_MOUSE_CONTROLS, pos))) {
		for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++) {
			kcMouse [i].u = FindNextItemUp (j, i, pos, ref);
			kcMouse [i].d = FindNextItemDown (j, i, pos, ref);
			kcMouse [i].l = FindNextItemLeft (j, i, pos, ref);
			kcMouse [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkHotkeyEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcHotkeys, NUM_HOTKEY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_HOTKEY_CONTROLS, pos))) {
		for (i = 0, j = NUM_HOTKEY_CONTROLS; i < j; i++) {
			kcHotkeys [i].u = FindNextItemUp (j, i, pos, ref);
			kcHotkeys [i].d = FindNextItemDown (j, i, pos, ref);
			kcHotkeys [i].l = FindNextItemLeft (j, i, pos, ref);
			kcHotkeys [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkTableEntries (int tableFlags)
{
	static int nLinked = 0;

if ((tableFlags & 1) && !(nLinked & 1))
	LinkKbdEntries ();
if ((tableFlags & 2) && !(nLinked & 2))
	LinkJoyEntries ();
if ((tableFlags & 4) && !(nLinked & 4))
	LinkMouseEntries ();
if ((tableFlags & 8) && !(nLinked & 8))
	LinkHotkeyEntries ();
nLinked |= tableFlags;
}

//------------------------------------------------------------------------------

int CControlConfig::HandleControl (void)
{
m_nPrevChangeMode = m_nChangeMode;
do {
	DrawScreen ();

	switch (m_nChangeMode) {
		case BT_KEY:
			m_nChangeMode = ChangeKey (m_items + m_nCurItem);
			break;
		case BT_MOUSE_BUTTON:
			m_nChangeMode = ChangeMouseButton (m_items + m_nCurItem);
			break;
		case BT_MOUSE_AXIS:
			m_nChangeMode = ChangeMouseAxis (m_items + m_nCurItem);
			break;
		case BT_JOY_BUTTON:
			m_nChangeMode = ChangeJoyButton (m_items + m_nCurItem);
			break;
		case BT_JOY_AXIS:
			if (m_nChangeMode != m_nPrevChangeMode)
				ControlsReadJoystick (m_startAxis);
			m_nChangeMode = ChangeJoyAxis (m_items + m_nCurItem);
			break;
		case BT_INVERT:
			m_nChangeMode = ChangeInvert (m_items + m_nCurItem);
			break;
		default:
			m_nChangeMode = BT_NONE;
		}
	m_nPrevChangeMode = m_nChangeMode;
	SDL_ShowCursor (1);
	GrUpdate (1);
	} while (m_nChangeMode != BT_NONE);
return m_nChangeMode;
}

//------------------------------------------------------------------------------

int CControlConfig::HandleInput (void)
{
	int		i, k;

k = KeyInKey ();
if (!m_bTimeStopped && (MultiMenuPoll () == -1))
	return -1;

m_nPrevItem = m_nCurItem;
switch (k) {
	case KEY_BACKSPACE:
		break;

	case KEY_COMMAND+KEY_SHIFTED+KEY_P:
	case KEY_ALTED+KEY_F9:
		SaveScreenShot (NULL, 0);
		break;

	case KEY_CTRLED+KEY_D:
		m_items [m_nCurItem].value = 255;
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_CTRLED+KEY_R:
		if (m_items == kcKeyboard) {
			for (i = 0; i < NUM_KEY_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [0][i];
				DrawItem (m_items + i, 0);
				}
			}
		else if (m_items == kcHotkeys) {
			for (i = 0; i < NUM_HOTKEY_CONTROLS; i++) {
				m_items [i].value = controlSettings.d2xDefaults [i];
				DrawItem (m_items + i, 0);
				}
			}
		else if (m_items == kcMouse) {
			for (i = 0; i < NUM_MOUSE_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [gameConfig.nControlType][i];
				DrawItem (m_items + i, 0);
				}
			}
		else {
			for (i = 0; i < NUM_JOY_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [gameConfig.nControlType][i];
				DrawItem (m_items + i, 0);
				}
			}
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_DELETE:
		m_items [m_nCurItem].value = 255;
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_UP:
	case KEY_PAD8:
		m_nCurItem = m_items [m_nCurItem].u;
		break;

	case KEY_DOWN:
	case KEY_PAD2:
		m_nCurItem = m_items [m_nCurItem].d;
		break;

	case KEY_LEFT:
	case KEY_PAD4:
		m_nCurItem = m_items [m_nCurItem].l;
		break;

	case KEY_RIGHT:
	case KEY_PAD6:
		m_nCurItem = m_items [m_nCurItem].r;
		break;

	case KEY_ENTER:
	case KEY_PADENTER:
		m_nChangeMode = m_items [m_nCurItem].nType;
		GameFlushInputs ();
		break;

	case KEY_ESC:
		return -1;
	}

m_nPrevMouseState = m_nMouseState;
m_nMouseState = MouseButtonState (0);
if ((m_nMouseState && !m_nPrevMouseState) || (m_nMouseState && m_nPrevMouseState)) {
	int item_height, mx, my;
	MouseGetPos (&mx, &my);
	mx -= m_xOffs;
	my -= m_yOffs;
//			my = (my * 12) / 10;	//y mouse pos is off here, no clue why
	for (i = 0; i < m_nItems; i++) {
		item_height = GetItemHeight (m_items + i);
		int x1 = CCanvas::Current ()->Left () + LHX (m_items [i].x) + LHX (m_items [i].w1);
		int x2 = x1 + LHX (m_items [i].w2);
		int y1 = CCanvas::Current ()->Top () + LHY (m_items [i].y);
		int y2 = y1 + /*LHY*/ (item_height);
		if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
			m_nCurItem = i;
			break;
			}
		}
	}
else if (!m_nMouseState && m_nPrevMouseState) {
	int item_height, mx, my;

	MouseGetPos (&mx, &my);
	mx -= m_xOffs;
	my -= m_yOffs;
	my = (my * 12) / 10;	//y mouse pos is off here, no clue why
	item_height = GetItemHeight (m_items + m_nCurItem);
	int x1 = CCanvas::Current ()->Left () + LHX (m_items [m_nCurItem].x) + LHX (m_items [m_nCurItem].w1);
	int x2 = x1 + LHX (m_items [m_nCurItem].w2);
	int y1 = CCanvas::Current ()->Top () + LHY (m_items [m_nCurItem].y);
	int y2 = y1 + /*LHY*/ (item_height);
	if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
		m_nChangeMode = m_items [m_nCurItem].nType;
		GameFlushInputs ();
		}
	else {
		int x1 = CCanvas::Current ()->Left () + m_closeX + LHX (1);
		int x2 = x1 + m_closeSize - LHX (1);
		int y1 = CCanvas::Current ()->Top () + m_closeY + LHX (1);
		int y2 = y1 + m_closeSize - LHY (1);
		if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
			return -1;
			}
		}
	}
return m_nCurItem;
}

//------------------------------------------------------------------------------

void CControlConfig::Edit (kcItem* items, int nItems)
{
	int i;

m_items = items;
m_nItems = nItems;
m_nPrevItem = -1;
m_nCurItem = 0;
m_nPrevMouseState =
m_nMouseState = 0;
m_nPrevChangeMode = 
m_nChangeMode = BT_NONE;
m_bTimeStopped = 0;
m_bRedraw = 0;
m_pszTitle = m_pszTitle;

paletteManager.SetEffect (0, 0, 0);
gameStates.menus.nInMenu++;
memset (m_startAxis, 0, sizeof (m_startAxis));

if (!IsMultiGame || (gameStates.app.nFunctionMode != FMODE_GAME) || gameStates.app.bEndLevelSequence) {
	m_bTimeStopped = 1;
	StopTime ();
	}

CCanvas::Push ();
CCanvas::SetCurrent (NULL);
CFont* font = CCanvas::Current ()->Font ();
FlushInput ();
backgroundManager.Setup (NULL, m_xOffs, m_yOffs, 640, 480);
//paletteManager.ResumeEffect ();
CCanvas::SetCurrent (NULL);

SDL_ShowCursor (1);
if (m_items == kcKeyboard)
	i = 0;
else if (m_items == kcJoystick)
	i = 1;
else if (m_items == kcMouse)
	i = 2;
else if (m_items == kcHotkeys)
	i = 3;
else
	i = -1;
if (i >= 0)
	LinkTableEntries (1 << i);

for (;;) {
	m_nChangeMode = HandleControl ();
	redbook.CheckRepeat ();
	MultiDoFrame ();
	m_nPrevItem = m_nCurItem;
	if (0 > (m_nCurItem = HandleInput ())) {
		Quit ();
		return;
		}
	if (m_nPrevItem != m_nCurItem) {
		SDL_ShowCursor (0);
		DrawItem (m_items + m_nPrevItem, 0);
		DrawItem (m_items + m_nCurItem, 1);
		SDL_ShowCursor (1);
		}
	}
Quit ();
}

//------------------------------------------------------------------------------

#include "screens.h"

void CControlConfig::Run (int nType, const char* pszTitle)
{
CBitmap*	bmSave;
int		i, j, b = gameOpts->legacy.bInput;

m_pszTitle = pszTitle;
m_xOffs = (CCanvas::Current ()->Width () - 640) / 2;
m_yOffs = (CCanvas::Current ()->Height () - 480) / 2;
if (m_xOffs < 0)
	m_xOffs = 0;
if (m_yOffs < 0)
	m_yOffs = 0;

gameOpts->legacy.bInput = 1;
SetScreenMode (SCREEN_MENU);
KCSetControls (0);
//save screen
if (gameOpts->menus.bFastMenus)
	bmSave = NULL;
else {
	bmSave = CBitmap::Create (0, CCanvas::Current ()->Width (), CCanvas::Current ()->Height (), 1);
	Assert (bmSave != NULL);
	bmSave->SetPalette (paletteManager.Texture ());
	CCanvas::Current ()->BlitClipped (bmSave, 0, 0, CCanvas::Current ()->Width (), CCanvas::Current ()->Width (), 0, 0);
	}
if (nType == 0)
	Edit (kcKeyboard, NUM_KEY_CONTROLS);
else if (nType == 1)
	Edit (kcJoystick, NUM_JOY_CONTROLS);
else if (nType == 2)
	Edit (kcMouse, NUM_MOUSE_CONTROLS);
#if 0
else if (nType == 3)
	Edit (kcSuperJoy, NUM_JOY_CONTROLS);
#endif
#ifdef D2X_KEYS
else if (nType == 4)
	Edit (kcHotkeys, NUM_HOTKEY_CONTROLS);
//end this section addition - VR
#endif
else {
	Int3 ();
	gameOpts->legacy.bInput = b;
	return;
	}

//restore screen
if (bmSave) {
	bmSave->BlitClipped (m_xOffs, m_yOffs);
	delete bmSave;
	}
// Update save values...
if (nType == 0) {
	for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++)
		controlSettings.custom [0][i] = kcKeyboard [i].value;
	}
else if (nType == 1) {
	if (gameOpts->input.joystick.bUse)
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++)
			controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
	}
else if (nType == 2) {
	if (gameOpts->input.mouse.bUse)
		for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++)
			controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
	}
else if (nType == 3) {
	if (gameConfig.nControlType == CONTROL_WINJOYSTICK)
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++)
			controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
	}
else if (nType == 4) {
	for (i=0, j = NUM_HOTKEY_CONTROLS; i < j; i++)
		controlSettings.d2xCustom [i] = kcHotkeys [i].value;
	}
gameOpts->legacy.bInput = b;
}

//------------------------------------------------------------------------------

fix Last_angles_p = 0;
fix Last_angles_b = 0;
fix Last_angles_h = 0;
ubyte Last_angles_read = 0;

int VR_sense_range [3] = { 25, 50, 75 };

#if 0
read_head_tracker ()
{
	fix yaw, pitch, roll;
	int buttons;

//------ read vfx1 helmet --------
	if (vfx1_installed) {
		vfx_get_data (&yaw,&pitch,&roll,&buttons);
	} else if (iglasses_headset_installed) {
		iglasses_read_headset (&yaw, &pitch, &roll);
	} else if (Victor_headset_installed)   {
		victor_read_headset_filtered (&yaw, &pitch, &roll);
	} else {
		return;
	}

	transformation.m_info.bUsePlayerHeadAngles = 0;
	if (Last_angles_read) {
		fix yaw1 = yaw;

		yaw1 = yaw;
		if ((Last_angles_h < (I2X (1)/4)) && (yaw > ((I2X (3))/4)))
			yaw1 -= I2X (1);
		else if ((yaw < (I2X (1)/4)) && (Last_angles_h > ((I2X (3))/4)))
			yaw1 += I2X (1);

		Controls [0].pitchTime	+= FixMul ((pitch- Last_angles_p)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
		Controls [0].headingTime+= FixMul ((yaw1 -  Last_angles_h)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
		Controls [0].bankTime	+= FixMul ((roll - Last_angles_b)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
	}
	Last_angles_read = 1;
	Last_angles_p = pitch;
	Last_angles_h = yaw;
	Last_angles_b = roll;
}
#endif

//------------------------------------------------------------------------------

void CExternalControls::Init (int intno, int address)
{
	int i;
	m_intno = intno;
	m_info = reinterpret_cast<ext_control_info*> ((size_t) address);
	m_bUse = 1;
	m_bEnable  = 1;

	i = FindArg ("-xname");
	if (i)
		m_name = StrDup (pszArgList [i + 1]);
	else
		m_name = StrDup ("External Controller");

   for (i = 0; i < (int) strlen (reinterpret_cast<char*> (m_name)); i++)
    if (m_name [i]=='_')
	  m_name [i]=' ';

	i = FindArg ("-xver");
	if (i)
		m_version = atoi (pszArgList [i+1]);
}

//------------------------------------------------------------------------------

void CExternalControls::Read (void)
{
	//union REGS r;
   int i;

	if (!m_bEnable) return;

if (m_version == 0)
	memset (m_info, 0, sizeof (ext_control_info));
else if (m_version > 0)  {

	if (m_version>=4)
		memset (m_info, 0, sizeof (advanced_ext_control_info));
   else if (m_version>0)
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64);
	else if (m_version>2)
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64 + sizeof (CFixVector) + sizeof (CFixMatrix) +4);

	if (m_version > 1) {
		// Write ship pos and angles to external controls...
		ubyte *temp_ptr = reinterpret_cast<ubyte*> (m_info);
		CFixVector *ship_pos;
		CFixMatrix *ship_orient;
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64 + sizeof (CFixVector)+sizeof (CFixMatrix));
		temp_ptr += sizeof (ext_control_info) + sizeof (CAngleVector) + 64;
		ship_pos = reinterpret_cast<CFixVector*> (temp_ptr);
		temp_ptr += sizeof (CFixVector);
		ship_orient = reinterpret_cast<CFixMatrix*> (temp_ptr);
		// Fill in ship postion...
		*ship_pos = OBJECTS [LOCALPLAYER.nObject].info.position.vPos;
		// Fill in ship orientation...
		*ship_orient = OBJECTS [LOCALPLAYER.nObject].info.position.mOrient;
		}
    if (m_version>=4) {
	   advanced_ext_control_info *temp_ptr = reinterpret_cast<advanced_ext_control_info*> (m_info);

      temp_ptr->headlightState = PlayerHasHeadlight (-1);
		temp_ptr->primaryWeaponFlags = LOCALPLAYER.primaryWeaponFlags;
		temp_ptr->secondaryWeaponFlags = LOCALPLAYER.secondaryWeaponFlags;
      temp_ptr->currentPrimary_weapon = gameData.weapons.nPrimary;
      temp_ptr->currentSecondary_weapon = gameData.weapons.nSecondary;
      temp_ptr->current_guidebot_command = gameData.escort.nGoalObject;
	   temp_ptr->force_vector=ExtForceVec;
		temp_ptr->force_matrix=ExtApplyForceMatrix;
	   for (i=0;i<3;i++)
       temp_ptr->joltinfo [i]=ExtJoltInfo [i];
      for (i=0;i<2;i++)
		   temp_ptr->x_vibrate_info [i]=ExtXVibrateInfo [i];
		temp_ptr->x_vibrate_clear=ExtXVibrateClear;
 	   temp_ptr->gameStatus=gameStates.app.nExtGameStatus;

      memset (&ExtForceVec, 0, sizeof (CFixVector));
      memset (&ExtApplyForceMatrix, 0, sizeof (CFixMatrix));

      for (i=0;i<3;i++)
		 ExtJoltInfo [i]=0;
      for (i=0;i<2;i++)
		 ExtXVibrateInfo [i]=0;
      ExtXVibrateClear=0;
		}
	}

	if (automap.Display ())			// (If in automap...)
		m_info->automapState = 1;
	//memset (&r,0,sizeof (r);

	if (gameData.multiplayer.nLocalPlayer > -1) {
		OBJECTS [LOCALPLAYER.nObject].mType.physInfo.flags &= (~PF_TURNROLL);	// Turn off roll when turning
		OBJECTS [LOCALPLAYER.nObject].mType.physInfo.flags &= (~PF_LEVELLING);	// Turn off leveling to nearest CSide.
		gameOpts->gameplay.nAutoLeveling = 0;

		if (m_version > 0) {
			CFixMatrix tempm, ViewMatrix;
			CAngleVector * Kconfig_abs_movement;
			char * oem_message;

			Kconfig_abs_movement = reinterpret_cast<CAngleVector*> ((size_t) m_info + sizeof (ext_control_info));

			if (!Kconfig_abs_movement->IsZero ()) {
				tempm = CFixMatrix::Create(*Kconfig_abs_movement);
				ViewMatrix = OBJECTS [LOCALPLAYER.nObject].info.position.mOrient * tempm;
				OBJECTS [LOCALPLAYER.nObject].info.position.mOrient = ViewMatrix;
			}
			oem_message = reinterpret_cast<char*> ((size_t) Kconfig_abs_movement + sizeof (CAngleVector));
			if (oem_message [0] != '\0')
				HUDInitMessage (oem_message);
		}
	}

	Controls [0].pitchTime += FixMul (m_info->pitchTime,gameData.time.xFrame);
	Controls [0].verticalThrustTime += FixMul (m_info->verticalThrustTime,gameData.time.xFrame);
	Controls [0].headingTime += FixMul (m_info->headingTime,gameData.time.xFrame);
	Controls [0].sidewaysThrustTime += FixMul (m_info->sidewaysThrustTime ,gameData.time.xFrame);
	Controls [0].bankTime += FixMul (m_info->bankTime ,gameData.time.xFrame);
	Controls [0].forwardThrustTime += FixMul (m_info->forwardThrustTime ,gameData.time.xFrame);
	Controls [0].rearViewDownCount += m_info->rearViewDownCount;
	Controls [0].rearViewDownState |= m_info->rearViewDownState;
	Controls [0].firePrimaryDownCount += m_info->firePrimaryDownCount;
	Controls [0].firePrimaryState |= m_info->firePrimaryState;
	Controls [0].fireSecondaryState |= m_info->fireSecondaryState;
	Controls [0].fireSecondaryDownCount += m_info->fireSecondaryDownCount;
	Controls [0].fireFlareDownCount += m_info->fireFlareDownCount;
	Controls [0].dropBombDownCount += m_info->dropBombDownCount;
	Controls [0].automapDownCount += m_info->automapDownCount;
	Controls [0].automapState |= m_info->automapState;

   if (m_version>=3)
	 {
		ubyte *temp_ptr = reinterpret_cast<ubyte*> (m_info);
		temp_ptr += (sizeof (ext_control_info) + sizeof (CAngleVector) + 64 + sizeof (CFixVector) + sizeof (CFixMatrix));

	   if (* (temp_ptr))
		 Controls [0].cyclePrimaryCount= (* (temp_ptr));
	   if (* (temp_ptr+1))
		 Controls [0].cycleSecondaryCount= (* (temp_ptr+1));

		if (* (temp_ptr+2))
		 Controls [0].afterburnerState= (* (temp_ptr+2));
		if (* (temp_ptr+3))
		 Controls [0].headlightCount= (* (temp_ptr+3));
  	 }
   if (m_version>=4)
	 {
	  advanced_ext_control_info *temp_ptr = reinterpret_cast<advanced_ext_control_info*> (m_info);

     if (temp_ptr->Reactor_blown)
      {
       if (gameData.app.nGameMode & GM_MULTI)
		    NetDestroyReactor (ObjFindFirstOfType (OBJ_REACTOR));
		 else
			 DoReactorDestroyedStuff (ObjFindFirstOfType (OBJ_REACTOR));
	   }
	}
}

//------------------------------------------------------------------------------

void CExternalControls::Destroy (void)
{
if (m_name) {
	delete[] m_name;
	m_name = NULL;
	}
}

//------------------------------------------------------------------------------

void KCSetControls (int bGet)
{
	int i, j;

SetControlType ();
return;
for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++) {
	if (bGet)
		controlSettings.custom [0][i] = kcKeyboard [i].value;
	else
		kcKeyboard [i].value = controlSettings.custom [0][i];
	}
//if ((gameConfig.nControlType > 0) && (gameConfig.nControlType < 5)) {
if (gameOpts->input.joystick.bUse) {
	for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
		else {
			kcJoystick [i].value = controlSettings.custom [gameStates.input.nJoyType][i];
			if (kcJoystick [i].nType == BT_INVERT) {
				if (kcJoystick [i].value != 1)
					kcJoystick [i].value = 0;
				controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
				}
			}
		}
	}
//else if (gameConfig.nControlType > 4 && gameConfig.nControlType < CONTROL_WINJOYSTICK) {
if (gameOpts->input.mouse.bUse) {
	for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
		else {
			kcMouse [i].value = controlSettings.custom [gameStates.input.nMouseType][i];
			if (kcMouse [i].nType == BT_INVERT) {
				if (kcMouse [i].value != 1)
					kcMouse [i].value = 0;
				controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
				}
			}
		}
	}
//else
if (gameConfig.nControlType == CONTROL_WINJOYSTICK) {
	for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
		else {
			kcSuperJoy [i].value = controlSettings.custom [gameConfig.nControlType][i];
			if (kcSuperJoy [i].nType == BT_INVERT) {
				if (kcSuperJoy [i].value!=1)
					kcSuperJoy [i].value	= 0;
				controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
				}
			}
		}
	}
for (i = 0, j = NUM_HOTKEY_CONTROLS; i < j; i++) {
	if (bGet)
		controlSettings.d2xCustom [i] = kcHotkeys [i].value;
	else
		kcHotkeys [i].value = controlSettings.d2xCustom [i];
	}
}

//------------------------------------------------------------------------------

int KcKeyboardSize (void) {return sizeofa (kcKeyboard);}
int KcMouseSize (void) {return sizeofa (kcMouse);}
int KcJoystickSize (void) {return sizeofa (kcJoystick);}
int KcSuperJoySize (void) {return sizeofa (kcSuperJoy);}
int KcHotkeySize (void) {return sizeofa (kcHotkeys);}

//------------------------------------------------------------------------------
//eof
